package com.yx.test3d.model;

import android.content.Context;
import android.opengl.GLES20;
import android.opengl.GLES30;
import android.opengl.Matrix;

import com.yx.test3d.bean.Obj3D;
import com.yx.test3d.light.DirectLight;
import com.yx.test3d.utils.LogUtils;
import com.yx.test3d.utils.ShaderUtil;

import java.util.ArrayList;
import java.util.List;

import static android.opengl.GLES20.GL_BACK;
import static android.opengl.GLES20.GL_COLOR_ATTACHMENT0;
import static android.opengl.GLES20.GL_DEPTH_ATTACHMENT;
import static android.opengl.GLES20.GL_DEPTH_BUFFER_BIT;
import static android.opengl.GLES20.GL_DEPTH_COMPONENT;
import static android.opengl.GLES20.GL_DEPTH_COMPONENT16;
import static android.opengl.GLES20.GL_FLOAT;
import static android.opengl.GLES20.GL_FRAMEBUFFER;
import static android.opengl.GLES20.GL_FRAMEBUFFER_COMPLETE;
import static android.opengl.GLES20.GL_FRONT;
import static android.opengl.GLES20.GL_NEAREST;
import static android.opengl.GLES20.GL_NONE;
import static android.opengl.GLES20.GL_REPEAT;
import static android.opengl.GLES20.GL_RGBA4;
import static android.opengl.GLES20.GL_TEXTURE0;
import static android.opengl.GLES20.GL_TEXTURE_2D;
import static android.opengl.GLES20.GL_TEXTURE_MAG_FILTER;
import static android.opengl.GLES20.GL_TEXTURE_MIN_FILTER;
import static android.opengl.GLES20.GL_TEXTURE_WRAP_S;
import static android.opengl.GLES20.GL_TEXTURE_WRAP_T;
import static android.opengl.GLES20.GL_UNSIGNED_BYTE;
import static android.opengl.GLES20.GL_UNSIGNED_INT;
import static android.opengl.GLES20.glActiveTexture;
import static android.opengl.GLES20.glBindFramebuffer;
import static android.opengl.GLES20.glBindTexture;
import static android.opengl.GLES20.glCheckFramebufferStatus;
import static android.opengl.GLES20.glClear;
import static android.opengl.GLES20.glCullFace;
import static android.opengl.GLES20.glGenFramebuffers;
import static android.opengl.GLES20.glGenTextures;
import static android.opengl.GLES20.glGetAttribLocation;
import static android.opengl.GLES20.glGetUniformLocation;
import static android.opengl.GLES20.glTexParameterf;
import static android.opengl.GLES20.glTexParameterfv;
import static android.opengl.GLES20.glTexParameteri;
import static android.opengl.GLES20.glUniform1f;
import static android.opengl.GLES20.glUniform1i;
import static android.opengl.GLES20.glUniform3fv;
import static android.opengl.GLES20.glUniformMatrix4fv;
import static android.opengl.GLES20.glViewport;
import static android.opengl.GLES30.GL_ARRAY_BUFFER;
import static android.opengl.GLES30.GL_COLOR_BUFFER_BIT;
import static android.opengl.GLES30.GL_STATIC_DRAW;
import static android.opengl.GLES30.GL_TRIANGLES;
import static android.opengl.GLES30.glBindBuffer;
import static android.opengl.GLES30.glBindVertexArray;
import static android.opengl.GLES30.glBufferData;
import static android.opengl.GLES30.glDrawArrays;
import static android.opengl.GLES30.glEnableVertexAttribArray;
import static android.opengl.GLES30.glFramebufferTexture2D;
import static android.opengl.GLES30.glGenBuffers;
import static android.opengl.GLES30.glGenVertexArrays;
import static android.opengl.GLES30.glTexImage2D;
import static android.opengl.GLES30.glUseProgram;
import static android.opengl.GLES30.glVertexAttribPointer;
import static android.opengl.GLES32.GL_CLAMP_TO_BORDER;
import static android.opengl.GLES32.GL_TEXTURE_BORDER_COLOR;

public class TestModel extends Model {
/*
    private static final String TAG = Cube.class.getSimpleName();
    int[] vao = new int[1];
    int[] vbo = new int[3];

    private int[] shadowVaos;
    private int[] shadowVbos;

    private int[] shadowFbo;
    private int[] colorTexture = new int[1];
    private int[] shadowTexture = new int[1];

    private int LOCATION_VERTEX;
    private int LOCATION_TEXTURE;
    private int LOCATION_NORMAL;
    private int LOCATION_MATRIX_M;
    private int LOCATION_MATRIX_V;
    private int LOCATION_MATRIX_P;
    private int LOCATION_MATRIX_N;
    private int LOCATION_MTL_KA;
    private int LOCATION_MTL_KD;
    private int LOCATION_MTL_KS;
    private int LOCATION_MTL_NS;
    private int LOCATION_LIGHT_DIR;
    private int LOCATION_LIGHT_KA;
    private int LOCATION_LIGHT_KD;
    private int LOCATION_LIGHT_KS;
    private int LOCATION_EYE;

    private int LOCATION_SHADOW_POSITION;
    private int LOCATION_SHADOW_MODEL;
    private int LOCATION_SHADOW_VIEW;
    private int LOCATION_SHADOW_PROJ;

    private int LOCATION_MAT_SHADOW_PROJ;
    private int LOCATION_MAT_SHADOW_VIEW;
    private int LOCATION_MAT_SHADOW_MAP;

    private float[] normalMatrix = new float[16];
    private float[] tempMatrix = new float[16];

    private float[] shadowProjMatrix = new float[16];
    private float[] shadowViewMatrix = new float[16];

    List<Obj3D> objectList =new ArrayList<>();


    public TestModel(List<Obj3D> data) {
        objectList =new ArrayList<>();
        objectList.addAll(data);
    }

    @Override
    public void setMatrix(float[] mMatrix, float[] vMatrix, float[] pMatrix) {
        super.setMatrix(mMatrix, vMatrix, pMatrix);

        //阴影的正交投影矩阵
        Matrix.orthoM(shadowProjMatrix, 0,
                -5, 5,
                -5, 5,
                1, 20);
        //将眼睛放到光的位置 设置投影
        float[] shadowEye=((DirectLight)light).dirction;
        Matrix.setLookAtM(shadowViewMatrix, 0,
                -shadowEye[0], -shadowEye[1], -shadowEye[2],
                0, 0, 0,
                0, 1, 0);


        Matrix.invertM(tempMatrix, 0, this.mMatrix, 0);
        Matrix.transposeM(normalMatrix, 0, tempMatrix, 0);
    }

    @Override
    public void onCreate(Context context) {
        vertexShaderCode = ShaderUtil.loadFromAssetsFile("shader/shadow_test.vert", context.getResources());
        fragmentShaderCode = ShaderUtil.loadFromAssetsFile("shader/shadow_test.frag", context.getResources());
//        fragmentShaderCode = ShaderUtil.loadFromAssetsFile("shader/shadow_show.frag", context.getResources());
        programId = ShaderUtil.createProgram(vertexShaderCode, fragmentShaderCode);

        String shadowVertexShaderCode = ShaderUtil.loadFromAssetsFile("shader/shadow.vert", context.getResources());
        String shadowFragmentShaderCode = ShaderUtil.loadFromAssetsFile("shader/shadow.frag", context.getResources());
        shadowProgramId = ShaderUtil.createProgram(shadowVertexShaderCode, shadowFragmentShaderCode);


        initLocation();


        initVAO();
        initShadowVAO();
        createDepathBuffer();
        //        initVBO();
    }

    private void initLocation() {
        LOCATION_VERTEX = glGetAttribLocation(programId, "v_position");
        LOCATION_TEXTURE = glGetAttribLocation(programId, "v_texCoords");
        LOCATION_NORMAL = glGetAttribLocation(programId, "v_normal");

        LOCATION_MATRIX_P = glGetUniformLocation(programId, "mat_proj");
        LOCATION_MATRIX_V = glGetUniformLocation(programId, "mat_view");
        LOCATION_MATRIX_M = glGetUniformLocation(programId, "mat_model");
        LOCATION_MATRIX_N = glGetUniformLocation(programId, "mat_normal");
        //计算阴影需要使用的参数
        LOCATION_MAT_SHADOW_PROJ = glGetUniformLocation(programId, "mat_shadow_proj");
        LOCATION_MAT_SHADOW_VIEW = glGetUniformLocation(programId, "mat_shadow_view");
        LOCATION_MAT_SHADOW_MAP = glGetUniformLocation(programId, "shadowMap");

        LOCATION_MTL_KA = glGetUniformLocation(programId, "material.ambient");
        LOCATION_MTL_KD = glGetUniformLocation(programId, "material.diffuse");
        LOCATION_MTL_KS = glGetUniformLocation(programId, "material.specular");
        LOCATION_MTL_NS = glGetUniformLocation(programId, "material.shininess");

        LOCATION_LIGHT_DIR = glGetUniformLocation(programId, "dirLight.direction");
        LOCATION_LIGHT_KA = glGetUniformLocation(programId, "dirLight.ambient");
        LOCATION_LIGHT_KD = glGetUniformLocation(programId, "dirLight.diffuse");
        LOCATION_LIGHT_KS = glGetUniformLocation(programId, "dirLight.specular");
        LOCATION_EYE = glGetUniformLocation(programId, "eye");

        //生成深度贴图着色器的参数
        LOCATION_SHADOW_POSITION = glGetAttribLocation(shadowProgramId, "v_position");
        LOCATION_SHADOW_MODEL = glGetUniformLocation(shadowProgramId, "mat_model");
        LOCATION_SHADOW_VIEW = glGetUniformLocation(shadowProgramId, "mat_view");
        LOCATION_SHADOW_PROJ = glGetUniformLocation(shadowProgramId, "mat_proj");

    }

    @Override
    public void onDraw() {

        glUseProgram(shadowProgramId);
        LogUtils.i("onDraw shadow programId: " + shadowProgramId);
        glUniformMatrix4fv(LOCATION_SHADOW_MODEL, 1, false, mMatrix, 0);
        glUniformMatrix4fv(LOCATION_SHADOW_VIEW, 1, false, shadowViewMatrix, 0);
        glUniformMatrix4fv(LOCATION_SHADOW_PROJ, 1, false, shadowProjMatrix, 0);

        glBindFramebuffer(GL_FRAMEBUFFER, shadowFbo[0]);
        glViewport(0, 0, 1024, 1024);
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
        glCullFace(GL_FRONT);
        for (int i = 0; i < objectList.size(); i++) {
            drawWithVAO(objectList.get(i),objectList.get(i).shadowVao);
        }
        glCullFace(GL_BACK); // 不要忘记设回原先的culling face

        glBindFramebuffer(GL_FRAMEBUFFER, GLES20.GL_NONE);

        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
        LogUtils.i("onDraw  programId: " + programId);
        glUseProgram(programId);
        glViewport(0, 0, width, height);

        glUniformMatrix4fv(LOCATION_MATRIX_M, 1, false, mMatrix, 0);
        glUniformMatrix4fv(LOCATION_MATRIX_V, 1, false, vMatrix, 0);
        glUniformMatrix4fv(LOCATION_MATRIX_P, 1, false, pMatrix, 0);
        glUniformMatrix4fv(LOCATION_MATRIX_N, 1, false, normalMatrix, 0);

        glUniformMatrix4fv(LOCATION_MAT_SHADOW_PROJ, 1, false, shadowProjMatrix, 0);
        glUniformMatrix4fv(LOCATION_MAT_SHADOW_VIEW, 1, false, shadowViewMatrix, 0);

        glUniform1i(LOCATION_MAT_SHADOW_MAP, 0);
        glActiveTexture(GL_TEXTURE0);//激活纹理
        glBindTexture(GL_TEXTURE_2D, shadowTexture[0]);//绑定纹理

        //设置平行光源方向
        glUniform3fv(LOCATION_LIGHT_DIR, 1, ((DirectLight) light).dirction, 0);
        glUniform3fv(LOCATION_LIGHT_KA, 1, light.ka, 0);
        glUniform3fv(LOCATION_LIGHT_KD, 1, light.kd, 0);
        glUniform3fv(LOCATION_LIGHT_KS, 1, light.ks, 0);

        //设置眼睛位置 用于计算镜面反射
        glUniform3fv(LOCATION_EYE, 1, eye.position, 0);

        for(int i = 0; i< objectList.size(); i++){
            glUniform3fv(LOCATION_MTL_KA, 1, objectList.get(i).mtl.Ka, 0);
            glUniform3fv(LOCATION_MTL_KD, 1, objectList.get(i).mtl.Kd, 0);
            glUniform3fv(LOCATION_MTL_KS, 1, objectList.get(i).mtl.Ks, 0);
            glUniform1f(LOCATION_MTL_NS, objectList.get(i).mtl.Ns);
            drawWithVAO(objectList.get(i),objectList.get(i).modelVao);
        }
    }

    @Override
    public void onDestroy() {
    }

    private void initVAO() {
        vao=new int[objectList.size()];
        vbo=new int[objectList.size()*3];
        glGenVertexArrays(vao.length, vao, 0);
        glGenBuffers(vbo.length, vbo, 0);
        for(int i = 0; i< objectList.size(); i++){
            Obj3D objectData=objectList.get(i);
            objectData.modelVao =vao[i];
            LogUtils.i("vao  "+ vao[i]);

            glBindVertexArray(vao[i]);
            glBindBuffer(GL_ARRAY_BUFFER, vbo[i*3]);
            glBufferData(GL_ARRAY_BUFFER, objectData.position.capacity() * 4, objectData.position, GL_STATIC_DRAW);
            glVertexAttribPointer(LOCATION_VERTEX, 3, GL_FLOAT, false, 0, 0);
            glEnableVertexAttribArray(LOCATION_VERTEX);

            glBindBuffer(GL_ARRAY_BUFFER, vbo[i*3+1]);
            glBufferData(GL_ARRAY_BUFFER, objectData.texture.capacity() * 4, objectData.texture, GL_STATIC_DRAW);
            glVertexAttribPointer(LOCATION_TEXTURE, 2, GL_FLOAT, false, 0, 0);
            glEnableVertexAttribArray(LOCATION_TEXTURE);


            glBindBuffer(GL_ARRAY_BUFFER, vbo[i*3+2]);
            glBufferData(GL_ARRAY_BUFFER, objectData.normal.capacity() * 4, objectData.normal, GL_STATIC_DRAW);
            glVertexAttribPointer(LOCATION_NORMAL, 3, GL_FLOAT, false, 0, 0);
            glEnableVertexAttribArray(LOCATION_NORMAL);

            glBindVertexArray(GL_NONE);

        }

    }

    private void initShadowVAO() {
        shadowVaos = new int[objectList.size()];
        shadowVbos = new int[objectList.size()];
        glGenVertexArrays(shadowVaos.length, shadowVaos, 0);
        glGenBuffers(shadowVbos.length, shadowVbos, 0);
        for (int i = 0; i < objectList.size(); i++) {
            Obj3D objectData = objectList.get(i);
            objectData.shadowVao = shadowVaos[i];
            glBindVertexArray(shadowVaos[i]);
            glBindBuffer(GL_ARRAY_BUFFER, shadowVbos[i]);
            glBufferData(GL_ARRAY_BUFFER, objectData.position.capacity() * 4, objectData.position, GL_STATIC_DRAW);
            glVertexAttribPointer(LOCATION_SHADOW_POSITION, 3, GL_FLOAT, false, 0, 0);
            glEnableVertexAttribArray(LOCATION_SHADOW_POSITION);

            glBindVertexArray(GL_NONE);
        }

    }


    private void createDepathBuffer() {
        *//*        int[] rbo=new int[1];
        glGenRenderbuffers(1,rbo,0);
        glBindRenderbuffer(GL_RENDERBUFFER,rbo[0]);
        glRenderbufferStorage(GL_RENDERBUFFER, GLES20.GL_RGBA4,1024,1024);
        glBindRenderbuffer(GL_RENDERBUFFER,0);*//*
        //生成纹理缓冲
        glGenTextures(1, colorTexture, 0);
        glBindTexture(GL_TEXTURE_2D, colorTexture[0]);
        glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
        glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
        glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
        glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
        glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA4, 1024, 1024, 0,GL_RGBA4, GL_UNSIGNED_BYTE, null);
        glBindTexture(GL_TEXTURE_2D, 0);

        //生成纹理缓冲
        glGenTextures(1, shadowTexture, 0);
        glBindTexture(GL_TEXTURE_2D, shadowTexture[0]);
        glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
        glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER);
        glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, new float[]{ 1, 1, 1, 1 },0);
        glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT16, 1024, 1024, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, null);
        glBindTexture(GL_TEXTURE_2D, 0);

        //生成帧缓冲  添加上面两个缓冲
        shadowFbo = new int[1];
        glGenFramebuffers(1, shadowFbo, 0);
        glBindFramebuffer(GL_FRAMEBUFFER, shadowFbo[0]);
//        glFramebufferRenderbuffer(GL_FRAMEBUFFER,GL_COLOR_ATTACHMENT0,GL_RENDERBUFFER,rbo[0]);
        glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, colorTexture[0],0);
        glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, shadowTexture[0], 0);
        int status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
        LogUtils.i(" framebuffer生成 " + status);
        if (status != GL_FRAMEBUFFER_COMPLETE) {
            // framebuffer生成失败
            LogUtils.i(" framebuffer生成 " + status);
        }

        // 切换到默认帧缓冲
        glBindFramebuffer(GL_FRAMEBUFFER, 0);
    }

    private void drawWithVAO(Obj3D objectData,int vao) {
        LogUtils.i(" draw vao  " + vao);
        glBindVertexArray(vao);
        glDrawArrays(GL_TRIANGLES, 0, objectData.position.limit() / 3);
        glBindVertexArray(GL_NONE);
    }*/
}
